﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Gray
{
   
    
    public partial class Form1 : Form
    {
        private HiPerfTimer myTimer;//定义HiPerfTimer类的方法
        private string curFileName;
        private System.Drawing.Bitmap curBitmap;
        public Form1()
        {
            InitializeComponent();
            myTimer = new HiPerfTimer();//实例化

        }

        private void Open_Click(object sender, EventArgs e)
        {
            //创建openFileDialog
            OpenFileDialog opnlg = new OpenFileDialog();
            opnlg.Filter = "所有图像｜*.bmp;*.pcx;*.png;*,jpg;*.gif|";


            //设置对话框标题
            opnlg.Title = "打开图像文件";
            //启动”帮助“按钮
            opnlg.ShowHelp = true;
            //如果结果为打开，选定文件
            if (opnlg.ShowDialog() == DialogResult.OK)
            {  curFileName = opnlg.FileName;    //读取当前选中的文件名
                //使用Image.fromFile创建图像对象
                try
                {
                    curBitmap = (Bitmap)Image.FromFile(curFileName);
                }
                catch(Exception exp)
                    {
                    MessageBox.Show(exp.Message); //抛出异常
                    }
            }
            var pathname = opnlg.FileName;
            this.pictureBox1.Load(pathname);
            Invalidate(); //对窗体进行重新绘制，这将强行执行paint事件处理程序 


        }

        private void Save_Click(object sender, EventArgs e)
        {
            if (curBitmap == null)
                return;
            SaveFileDialog savelog = new SaveFileDialog(); //调用saveFileDialog
            savelog.Title = "保存为"; //设置对话标题
            savelog.OverwritePrompt = true; //改写已存在文件时提示用户
            savelog.Filter = "BMP文件(*.bmp)|*.bmp|" + "Gif文件（*.gif)|*.gif|" + "JPEG文件(*.jpg)|*.jpg"; //为图像选择一个筛选器
            savelog.ShowHelp = true; //启动帮助按钮
            //如果选择了格式，则保存图像
            
            if (savelog.ShowDialog() == DialogResult.OK)
            {
                string fileName = savelog.FileName; //获取用户选择文件
                string strFileExtn = fileName.Remove(0, fileName.Length - 3); //获取用户选择文件的扩展名
                switch (strFileExtn) //保存文件
                {
                    case "bmp":  //bmp格式
                        curBitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Bmp); break;
                    case "jpg": //jpg格式
                        curBitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Jpeg); break;
                    case "gif": //gif格式
                        curBitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Gif); break;
                    
                    default: break;
                }
            }
        }


        private void Close_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            //获取Graphics对象
            Graphics g = e.Graphics;
            if (curBitmap != null)
            {
                //使用DrawImage方法绘制图像
                //160，20：显示在主窗体内，图像左上角的坐标
                //curBitmap.Width,curBitmap.Height:图像的宽度和高度
                
                g.DrawImage(curBitmap, 160, 20, curBitmap.Width, curBitmap.Height);
            }

        }

        private void pixel_Click(object sender, EventArgs e)
        {
            //启动计时器
            myTimer.Start();

            Color curColor;
            int Gray;
            if(curBitmap==null)//如果图片为空，直接反回
            {
                return;
            }
            for(var i=100;i<curBitmap.Width;i++)//二维图像数组循环 行列
            {
                for(var j=100;j<curBitmap.Height;j++)//二维图像数组循环 纵列
                {
                    curColor = curBitmap.GetPixel(i, j); //获取该点像素的RGB颜色值
                    Gray = (int)(curColor.R * 0.229 + curColor.G * 0.587 + curColor.B * 0.114);//利用公式计算灰度值
                    curBitmap.SetPixel(i, j, Color.FromArgb(Gray, Gray, Gray));//设置该点像素的灰度值 R=G=B=Gray
                }
            }
            Invalidate();//对窗体进行重新绘制，这将强制执行Paint事件处理

            //关闭计时器
            myTimer.Stop();
            //在TextBox内显示计时时间
            timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";
        }

        private void menory_Click(object sender, EventArgs e)
        {
            //启动计时器
            myTimer.Start();

            if (curBitmap != null)
            {
                ////位图矩形
                //Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
                ////以可读写方式锁定全部位图像素
                //BitmapData bmpData = curBitmap.LockBits(rect, ImageLockMode.ReadWrite, curBitmap.PixelFormat);
                ////获得首地址
                //IntPtr ptr = bmpData.Scan0;

                //int bytes = curBitmap.Width * curBitmap.Height * 3;

                ////定义位图数组
                //byte[] rgbValues = new byte[bytes];
                ////复制被锁定的位图像素值到该数组内
                //Marshal.Copy(ptr, rgbValues, 0, bytes);
                ////灰度化
                //double colorTemp = 0;

                //for(int i=0;i<rgbValues.LongLength;i+=3)
                //{
                //    //利用公式计算灰度值
                //    colorTemp = rgbValues[i + 2] * 0.229 + rgbValues[i + 1] * 0.587 + rgbValues[i] * 0.114;
                //    //R=G=b
                //    rgbValues[i] = rgbValues[i + 1] = rgbValues[i + 2] = (byte)colorTemp;
                //}
                ////把数组复制加位图
                //Marshal.Copy(rgbValues, 0, ptr, bytes);
                ////解锁位图像素
                //curBitmap.UnlockBits(bmpData);
                ////对窗体进行重新绘制，这将强制执行Paint事件处理
                //Invalidate();




                Rectangle rect = new Rectangle(0, 0, curBitmap.Width*3/4, curBitmap.Height*3/4);
                BitmapData bmpData = curBitmap.LockBits(rect, ImageLockMode.ReadWrite, curBitmap.PixelFormat);
                IntPtr ptr = bmpData.Scan0;
                int bytes = bmpData.Stride * bmpData.Height;
                byte[] rgbValues = new byte[bytes];
                Marshal.Copy(ptr, rgbValues, 0, bytes);
                double colorTemp = 0;
                for(int i=0;i<bmpData.Height;i++)
                {
                    for(int j=0;j<bmpData.Width*3;j+=3)
                    {
                        colorTemp = rgbValues[i * bmpData.Stride + j + 2] * 0.229 +
                                rgbValues[i * bmpData.Stride + j + 1] * 0.587 +
                                 rgbValues[i * bmpData.Stride + j] * 0.114;
                        rgbValues[i * bmpData.Stride + j + 2] = rgbValues[i * bmpData.Stride + j + 1] = rgbValues[i * bmpData.Stride + j] = (byte)colorTemp;


                    }
                }
                Marshal.Copy(rgbValues, 0, ptr, bytes);
                curBitmap.UnlockBits(bmpData);
                Invalidate();

                //关闭计时器
                myTimer.Stop();
                //在TextBox内显示计时时间
                timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";
            }
        }

        private void pointer_Click(object sender, EventArgs e)
        {

            //启动计时器
            myTimer.Start();

            if (curBitmap!=null)
            {
                Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
                BitmapData bmpData = curBitmap.LockBits(rect, ImageLockMode.ReadWrite, curBitmap.PixelFormat);
                byte temp = 0;
                //启动不安全模式
                unsafe
                {
                    //获得首地址
                    byte* ptr = (byte*)(bmpData.Scan0);
                    //二维图像循环
                    for (int i = 0; i < bmpData.Height; i++)
                    {
                        for (int j = 0; j < bmpData.Width; j++)
                        {
                            //利用公式计算灰度
                            temp = (byte)(0.229 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);
                            //R=G=B

                            ptr[2] = ptr[1] = ptr[0] = temp;
                            //指向下一个像素
                            ptr += 3;
                            //指向下一行数组的首个字节
                            ptr += bmpData.Stride - bmpData.Width * 3;
                        }
                    }
                    //解锁位图像素
                    curBitmap.UnlockBits(bmpData);
                    //对窗体进行重新绘制，这将强制执行Paint事件处理
                    Invalidate();

                    //关闭计时器
                    myTimer.Stop();
                    //在TextBox内显示计时时间
                    timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";
                }
            }
        }
    }
}
